/*
 * Dijjer - A Peer to Peer HTTP Cache
 * Copyright (C) 2004,2005 Change.Tv, Inc, Mathias De Maré
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package dijjer.io.comm;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Set;

import dijjer.AbstractFactory;
import dijjer.Dijjer;
import dijjer.util.logging.Logger;

public class WebRoutingTable extends AbstractRoutingTable {
	
	public WebRoutingTable(int maxSize, final AbstractUdpSocketManager usm, Set seedNodes, boolean noRapidPing,
			boolean allowsLocal, String localNetwork) throws Exception {
		super(maxSize, usm, seedNodes, noRapidPing, allowsLocal, localNetwork);
	}

	public WebRoutingTable(int routingTableSize) throws Exception {
		this(routingTableSize, AbstractFactory.getFactory().getUdpSocketManager(), Dijjer.getDijjer().getSeedNodes(), Dijjer
				.getDijjer().isRapidPingDisabled(), Dijjer.getDijjer().getUseLocalNetwork(), Dijjer.getDijjer()
				.getLocalNetwork());
	}

	public boolean isBadAddress(AbstractPeer peer) {
		WebPeer wp = (WebPeer) peer;
		InetAddress inet = wp.getAddress();
		if(inet.isLinkLocalAddress() // 169.254.x.x dhcp auto config ips
		|| inet.isLoopbackAddress() // 127.x.x.x loopback net
		|| inet.isAnyLocalAddress() // 0.0.0.0
		|| inet.isMulticastAddress()) // class D ips
			return true;
		
		if(inet.isSiteLocalAddress()) { // 192.168.x.x and other internal ips
			try {
				int slash = _localNetwork.indexOf('/');
				String localNetwork = _localNetwork.substring(0, slash);
				int cidr = Integer.parseInt(_localNetwork.substring(slash+1, _localNetwork.length()));
				
				byte[] hostBytes = inet.getAddress();
				byte[] networkBytes = InetAddress.getByName(localNetwork).getAddress();
				
				if(hostBytes.length != networkBytes.length) //ipv4 versus ipv6
					return true;
				else {
					//convert from cidr to netmask
					byte[] maskBytes = new byte[hostBytes.length];
					for(int i=0; i<maskBytes.length;i++) {
						maskBytes[i] = 0x00;
						for(int j=0; j<8; j++) {
							if(i*8+j<cidr) {
								maskBytes[i] |= (1 << j);
							}
						}
					}
					for(int i=0; i<hostBytes.length;i++) {
						if((networkBytes[i] & maskBytes[i]) != hostBytes[i])
							return true;
					}
					return false;
				}
			}
			catch(UnknownHostException e) {
				Logger.warning("Could not find hostname for local address", e);
			}
		}
		return false;
	}

	public boolean isUs(AbstractPeer p) {
		WebPeer wp = (WebPeer) p;
		if ((wp.getAddress().isAnyLocalAddress() || wp.getAddress().isLoopbackAddress() || wp.getAddress().isLinkLocalAddress())
				&& (wp.getPort() == ((WebPeer) getPeer()).getPort() || wp.getPort() == 0))
			return true;
		return false;
	}

	public boolean sameSubnet(AbstractPeer me, AbstractPeer them) {
		String mip = ((WebPeer) me).getAddress().getHostAddress().trim();
		mip = ((WebPeer) _peer).getAddress().getHostAddress().trim();
		String tip = ((WebPeer) them).getAddress().getHostAddress().trim();
		int matched = 0;
		while ( (matched < mip.length()) && (matched < tip.length())
		&& (mip.charAt(matched) == tip.charAt(matched)) ) {
			matched++;
		}
		if (matched > mip.lastIndexOf('.', mip.lastIndexOf('.') - 1))
			return true;
		return false;
	}
	
	public static void init(int routingTableSize) throws Exception {
		_rt = new WebRoutingTable(routingTableSize);
	}

}
